package entries

import (
	"fmt"

	"gitee.com/cjianwen/go/demo/socks_v2/raft_demo/server/consts"
	"gitee.com/cjianwen/go/demo/socks_v2/raft_demo/server/global"
	"gitee.com/cjianwen/go/demo/socks_v2/raft_demo/server/types"
	"gitee.com/cjianwen/go/service"
)

type entries struct {
	*service.Module
	commitIdx uint32 // 已提交的索引值，从0开始，提交一个变为1
	// receiveIdx uint   // 收到的最大索引值
	datas []*types.EntryItem
}

func (e *entries) GetCommitIdx() uint32 {
	return e.commitIdx
}

// 返回数据的索引
func (e *entries) AppendEntries(data *types.EntryItem) uint32 {
	idx := uint32(len(e.datas))
	e.datas = append(e.datas, data)
	return idx
}

func (e *entries) UpdateEntries(idx uint32, data *types.EntryItem) error {
	if idx < uint32(len(e.datas)) {
		e.datas[idx] = data
	} else if idx == uint32(len(e.datas)) {
		e.AppendEntries(data)
	} else {
		return fmt.Errorf("UpdateEntries error, idx = %d, len = %d", idx, len(e.datas))
	}
	return nil
}

func (e *entries) GetEntryItem(idx uint32) *types.EntryItem {
	if idx < uint32(len(e.datas)) {
		return e.datas[idx]
	}
	return nil
}

func (e *entries) GetEntryItemId(idx uint32) uint32 {
	i := e.GetEntryItem(idx)
	if i != nil {
		return i.Id
	}
	return 0
}

func (e *entries) GetEntryItemTerm(idx uint32) uint32 {
	i := e.GetEntryItem(idx)
	if i != nil {
		return i.Term
	}
	return 0
}

func (e *entries) Commit(dataIdx uint32) error {
	if len(e.datas) < int(dataIdx) || len(e.datas) < int(e.commitIdx) {
		return fmt.Errorf("Commit error, data is not enough length, idx = %d, len = %d, commitIdx = %d", dataIdx, len(e.datas), e.commitIdx)
	}

	for i := e.commitIdx; i < dataIdx; i++ {
		if e.datas[i] == nil {
			return fmt.Errorf("Commit error, have nil data, idx = %d, len = %d", i, len(e.datas))
		}
	}
	e.commitIdx = dataIdx
	return nil
}

func (e *entries) GetIndex() uint32 {
	return uint32(len(e.datas))
}

func (e *entries) Init() error {
	return nil
}

func (e *entries) Run() error {
	return nil
}

func (e *entries) Final() error {
	return nil
}

func init() {
	module := &service.Module{Name: "Entries", ModuleId: consts.MID_Entries}
	e := &entries{Module: module}
	global.DataEntries = e
	service.RegisterModule(e)
}
